type label = E | NE | N | NW | W | SW | S | SE | NO_DIR

let label_to_int value = match value with
	  E      -> 0
	| NE     -> 1
	| N      -> 2
	| NW     -> 3
	| W      -> 4
	| SW     -> 5
	| S      -> 6
	| SE     -> 7
	| NO_DIR -> 8
	
let int_to_label value = match value with
	  0 -> E
	| 1 -> NE
	| 2 -> N
	| 3 -> NW
	| 4 -> W
	| 5 -> SW
	| 6 -> S
	| 7 -> SE
	| _ -> NO_DIR
	
let label_to_string value = match value with
	  E      -> "E"
	| NE     -> "NE"
	| N      -> "N"
	| NW     -> "NW"
	| W      -> "W"
	| SW     -> "SW"
	| S      -> "S"
	| SE     -> "SE"
	| NO_DIR -> ""	

type 'a edge = Initial of 'a | Final | Transition of label * 'a
type vertex = Empty | State of int * (vertex edge)

let rec add_state new_id new_dir automaton = match automaton with
	  Initial Empty                         -> Initial (State (new_id, Final))
	| Initial (State (id, trans))           -> Initial (State (id, (add_state new_id new_dir trans)))
	| Transition (label, Empty)             -> Final
	| Transition (label, State (id, trans)) -> Transition (label, State (id, add_state new_id new_dir trans))
	| Final 						                -> Transition (new_dir, State (new_id, Final))
	
let rec print automaton = match automaton with
	  Initial Empty                         -> print_string "----> Empty\n"
	| Initial (State (id, trans))           -> print_string "----> "; print_int id; print trans
	| Transition (label, Empty)             -> print_string " --"; print_string (label_to_string label); print_string "-->\n"
	| Transition (label, State (id, trans)) -> print_string " --"; print_string (label_to_string label); print_string "--> "; print_int id; print trans
	| Final 						                -> print_string " ---->\n"

let rec to_string automaton = match automaton with
	  Initial Empty                         -> "<"
	| Initial (State (id, trans))           -> "<"^(to_string trans)
	| Transition (label, Empty)             -> ">"
	| Transition (label, State (id, trans)) -> (string_of_int(label_to_int label))^(to_string trans)
	| Final 						                -> ">"

class t_automaton =
object (this)
	(* Variables membres de la classe *)
	val mutable nb_state = 1
	val mutable gesture = 0
	val mutable initial = add_state 0 NO_DIR (Initial Empty)
	val mutable current = Initial Empty
	val mutable last_dir = NO_DIR
	val mutable last_dir_rec = NO_DIR
	(* Methodes de la classe *)
	method is_empty = (initial = Initial Empty) || (initial = Initial (State (0, Final)))
	method get_gesture = gesture
	method set_gesture new_gesture = gesture <- new_gesture
	method clear = nb_state <- 0;
	method reset = current <- initial; last_dir <- NO_DIR
	method reset_rec = last_dir_rec <- NO_DIR
	method build new_dir =
		if ((new_dir <> last_dir_rec) && (new_dir <> NO_DIR)) then
			(initial <- add_state nb_state new_dir initial;
			nb_state <- nb_state + 1;
			last_dir_rec <- new_dir)
	method eval new_dir =
		match current with
		  Initial Empty                         -> this#reset; false
		| Initial (State (id, Final))           -> this#reset; false
		| Initial (State (id, trans))           -> current <- trans; this#eval new_dir
		| Transition (label, Empty)             -> this#reset; false
		| Transition (label, State (id, trans)) ->
			(if ((new_dir <> last_dir) && (new_dir <> NO_DIR)) then
				if (new_dir = label) then (current <- trans; last_dir <- new_dir; this#eval new_dir)
				else (this#reset; false)
			else false)
		| Final                                 -> this#reset; true	
	method print = print initial
	method to_string = to_string initial
end
